Framebuffer Objects
Motivation
FBO
Framework
Examples
Do-Nothing
void draw(){

    globs->prog.use();
    globs->fbo.setAsRenderTarget(true);
    globs->camera.setUniforms();
    globs->lightManager.setUniforms();

    Program::setUniform("worldMatrix", mat4::identity() );
    globs->dungeon.draw();
    globs->fbo.unsetAsRenderTarget();

    globs->fboprog.use();
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    globs->fbo.texture->bind(0);
    globs->fsq.draw();

}
VS
layout(location=0) in vec3 position;
layout(location=1) in vec2 texcoord;

out vec2 v_texCoord;

void main(){
    gl_Position = vec4( position.xy, -1.0, 1.0 );
    v_texCoord = texcoord;
}
FS
in vec2 v_texCoord;
out vec4 color;

layout(binding=0) uniform sampler2DArray tex;

void main(){
    color = texture( tex, vec3(v_texCoord,0.0) );
}
Results
do-nothing.png
Color Manipulation
vec3 rgb2hsv(vec3 color)
{
    float r=color.r;
    float g=color.g;
    float b=color.b;
    float mx = max(r,max(g,b));
    float mn = min(r,min(g,b));
    float h,s,v;

    v = mx;    //value
    if(mx != 0.0 ){
        s = (mx-mn)/mx;    //saturation
        if(r == mx)
            h = (g-b)/(mx-mn);
        else if(g == mx)
            h = 2.0+(b-r)/(mx-mn);
        else
            h = 4.0+(r-g)/(mx-mn);
        h *= 60.0;
        if( h < 0.0 )
            h += 360.0;
    } else {
        h=s=0.0;
    }
    return vec3(h,s,v);
}
Color Manipulation
vec3 hsv2rgb(vec3 hsv)
{
    float h = hsv[0];
    float s = hsv[1];
    float v = hsv[2];
    float r,g,b;
    if(s == 0.0)
        r=g=b=v;
    else{
        h=h/60.0;
        float ipart = floor(h);
        float fpart = h-ipart;
        float A=v*(1.0-s);
        float B=v*(1.0-s*fpart);
        float C=v*(1.0-s*(1.0-fpart));
        if(ipart == 0.0){
            r=v; g=C; b=A;
        } else if( ipart==1.0){
            r=B; g=v; b=A;
        } else if( ipart==2.0 ){
            r=A; g=v; b=C;
        } else if( ipart==3.0){
            r=A; g=B; b=v;
        } else if( ipart==4.0 ){
            r=C; g=A; b=v;
        } else {
            r=v; g=A; b=B;
        }
    }
    return vec3(r,g,b);
}
Color Manipulation
void main(){
    color = texture( tex, vec3(v_texCoord,0.0) );
    vec3 tmp = rgb2hsv(color.rgb);
    tmp[1] += deltaSaturation;
    tmp[1] = clamp(tmp[1],0.0,1.0);
    color.rgb = hsv2rgb(tmp);
}
Results
desaturate-1.png desaturate-2.png desaturate-3.png desaturate-4.png
Example
vec4 online = texelFetch( tex, ivec3( gl_FragCoord.xy, 0 ), 0 );
vec4 aboveline = texelFetch( tex, ivec3( gl_FragCoord.x, gl_FragCoord.y-1.0, 0 ), 0 );
vec4 belowline = texelFetch( tex, ivec3( gl_FragCoord.x, gl_FragCoord.y+1.0, 0 ), 0 );
int y = int(gl_FragCoord.y);
switch( y%4 ){
    case 0: color = online; break;
    case 1: color = 0.5 * aboveline; break;
    case 2: color = vec4(0.0, 0.0, 0.0, 1.0); break;
    case 3: color = 0.5 * belowline; break;
}
color.a = 1.0;
Results
badtv.jpg
Example
in vec2 v_texCoord;
out vec4 color;

layout(binding=0) uniform sampler2DArray tex;

void main(){
    vec4 tmp = texture( tex, vec3(v_texCoord,0.0) );
    tmp = floor( tmp * 8.0 ) / 8.0;
    color = vec4(tmp.xyz,1.0);
}
Results
posterize.png
Pixelated
in vec2 v_texCoord;
out vec4 color;

layout(binding=0) uniform sampler2DArray tex;

void main(){
    //assumes FBO size matches screen size
    ivec2 coord = ivec2(gl_FragCoord.xy);
    coord = coord & ivec2(~15);
    vec4 texcolor = texelFetch( tex, ivec3(coord,0), 0 );
    color = texcolor;
}
Results
pixelated.png
Dot Matrix
in vec2 v_texCoord;
out vec4 color;

layout(binding=0) uniform sampler2DArray tex;

void main(){
    float incr = 1.0/32.0;
    vec2 tmp = v_texCoord / vec2(incr);
    tmp = floor(tmp);
    tmp *= incr;
    tmp += incr * 0.5;
    float dist = distance(tmp,v_texCoord);
    vec4 texcolor = texture(tex, vec3(tmp,0));
    float ramp = 1.0 - smoothstep( incr*0.2, incr*0.5, dist );
    color.rgb = ramp * texcolor.rgb;
    color.a = texcolor.a;
}
Results
dotmatrix.png
Example
Example
Example
void draw(){
    globs->prog.use();
    if( isFading ){
        globs->fbo.setAsRenderTarget(false);
        globs->cam1.setUniforms();
        drawObjects();
        globs->fbo2.setAsRenderTarget(true);
        globs->cam2.setUniforms();
        drawObjects();
        globs->fbo2.unsetAsRenderTarget();
        globs->fboprog.use();
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        globs->fbo.texture->bind(0);
        globs->fbo2.texture->bind(1);
        Program::setUniform("fadePercent",fadePercent);
        globs->fullscreenquad.draw();
    } else {
        globs->camera.setUniforms();
        drawObjects();
    }
}
Example
in vec2 v_texCoord;
out vec4 color;

layout(binding=0) uniform sampler2DArray tex1;
layout(binding=1) uniform sampler2DArray tex2;

void main(){
    vec4 c1 = texture( tex1, vec3(v_texCoord,0.0) );
    vec4 c2 = texture( tex2, vec3(v_texCoord,0.0) );
    color = mix( c1, c2, fadePercent );
}
Results
crossfade1.png crossfade2.png crossfade3.png
Example
Example
Example
void draw(){
    globs->prog.use();
    if( isFlipping ){
        globs->fbo.setAsRenderTarget(false);
        drawObjects();
        globs->fbo.unsetAsRenderTarget();
        globs->fboprog.use();
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        globs->fbo.texture->bind(0);
        if( flipPercent < 0.5 )
            Program::setUniform("worldMatrix", scaling( 1.0-flipPercent*2.0,1,1) );
        else
            Program::setUniform("worldMatrix", scaling( (flipPercent-0.5)*2.0,1,1) );
        globs->fullscreenquad.draw();
    } else {
        drawObjects();
    }
}
Example
out vec2 v_texCoord;
void main(){
    vec4 p = vec4(position.xy,0,1);
    p = p * worldMatrix;
    gl_Position = vec4( p.xy, -1.0, 1.0 );
    v_texCoord = texcoord;
}
Results
cutscene1.png cutscene2.png cutscene3.png
Example
Results
bman1.png bman2.png bman3.png
Edge Detection
Edge Detection
edgedetect.png
Sources